package zpe.genericcrud.service;


import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import zpe.genericcrud.dao.GenericDaoJpa;
import zpe.genericcrud.exception.ApplicationException;
import zpe.genericcrud.model.Entidade;

/**
 * Servi�o gen�rico que implementa os m�todos do ServiceCrud
 * @author Samuel Soares
 *
 * @param <E> Entidade gerenciada por esse service
 */
// @org.springframework.stereotype.Service("genericServiceJpa")
@SuppressWarnings("serial")
public class GenericServiceJpa<E extends Entidade> implements ServiceCrud<E>{

	/** Dao utilizado para acesso ao banco de dados. */
	// @Autowired @Qualifier("daoJpa")
	protected GenericDaoJpa<E> dao;
	
	@Override
	public List<E> findAll( Class<E> clazz ) {
		return dao.findAll(clazz);
	}

	@Override
	public List<E> findAll( Class<E> clazz, String campoOrdenacao ) {
		return dao.findAll( clazz, campoOrdenacao );
	}
	
	@Override @Deprecated
	public List<E> findByExample(E obj) {
		throw new UnsupportedOperationException("M�todo n�o suportado pelo provedor.");
	}

	@Override
	public E findByPrimaryKey(Class<E> clazz, Serializable id) {
		return (E)dao.findByPrimaryKey(clazz, id);
	}

	@Override
	@Transactional( propagation = Propagation.REQUIRED, rollbackFor = RuntimeException.class )
	public E insert(E obj) {
		return dao.insert(obj);
	}

	@Override
	@Transactional( propagation = Propagation.REQUIRED, rollbackFor = RuntimeException.class )
	public void insertAll(Collection<E> collection) {
		dao.insertAll(collection);		
	}

	@Override
	@Transactional( propagation = Propagation.REQUIRED, rollbackFor = RuntimeException.class )
	public void remove(E obj) {
		try{
			dao.remove(obj);
		}catch (Exception e) {
			throw new ApplicationException("O registro n�o pode ser removido. Verifique se existem itens dependentes desse registro.");
		}
	}

	@Override
	@Transactional( propagation = Propagation.REQUIRED, rollbackFor = RuntimeException.class )
	public void removeAll(Collection<E> collection) {
		try{
			dao.removeAll(collection);
		}catch (Exception e) {
			throw new ApplicationException("O registro n�o pode ser removido. Verifique se existem itens dependentes desse registro.");
		}
	}

	@Override
	@Transactional( propagation = Propagation.REQUIRED, rollbackFor = RuntimeException.class )
	public E update(E obj) {
		return dao.update(obj);
	}

	@Override
	@Transactional( propagation = Propagation.REQUIRED, rollbackFor = RuntimeException.class )
	public void updateAll(Collection<E> collection) {
		dao.updateAll(collection);
	}

	@Override
	public List<E> startsWith( Class<E> clazz, String strStart ){
		return dao.startsWith(clazz, strStart);
	}

	@Override
	public List<E> startsWithAndFilter( Class<E> clazz, String strStart, Map<String, Object> filter ){
		return dao.startsWithAndFilter(clazz, strStart, filter);
	}
	
	@Override
	public List<E> findByFilter(Class<E> clazz, Map<String, Object> filter) {
		return dao.findByFilter(clazz, filter);
	}
	
	@Override
	public List<E> findByFilter(Class<E> clazz, Map<String, Object> filter, String campoOrdenacao) {
		return dao.findByFilter(clazz, filter, campoOrdenacao);
	}
	
	@Override @SuppressWarnings({ "unchecked", "rawtypes" })
	public List<E> find(E entidade, String strStart, Map<String, Object> filter ){
		List<E> list = null;
		Map<String, Object> map = entidade.notEmptyFields(); 
		if( strStart != null ){
			if( map == null || map.isEmpty() ){
				list = dao.startsWith((Class)entidade.getClass(), strStart );
			}else{
				list = dao.startsWithAndFilter( (Class)entidade.getClass(), strStart, entidade.notEmptyFields() );
			}
		}else if( map != null && !entidade.notEmptyFields().isEmpty() ){
			list = dao.findByFilter( (Class)entidade.getClass(), entidade.notEmptyFields() );
		}
		if( list.isEmpty() ){
			throw new ApplicationException( "Itens n�o encontrados." );
		}
		return list;
	}

	/**
	 * Dao gen�rico utilizado no acesso ao banco de dados.
	 * @return
	 */
	public GenericDaoJpa<E> getDao() {
		return dao;
	}
	
	public void setDao(GenericDaoJpa<E> dao) {
		this.dao = dao;
	}
}